<?php

/**
 * Thrive Themes - https://thrivethemes.com
 *
 * @package thrive-dashboard
 */
if ( ! defined( 'ABSPATH' ) ) {
	exit; // Silence is golden!
}

require_once __DIR__ . "/ConvertKit/Exception.php";

class Thrive_Dash_Api_ConvertKit {

	protected $api_version    = 'v3';
	protected $api_url_base   = 'https://api.convertkit.com/';
	protected $resources      = array();
	protected $markup         = array();
	protected $_existing_tags = array();

	protected $key;


	public function __construct( $key ) {

		if ( empty( $key ) ) {
			throw new Thrive_Dash_Api_ConvertKit_Exception( 'Invalid API credentials' );
		}

		$this->key = $key;
	}

	/**
	 * get forms from the API
	 *
	 * @return array|mixed
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	public function get_forms() {
		$response = $this->_call( 'forms' );

		$forms = isset( $response['forms'] ) ? $response['forms'] : array();

		if ( isset( $response['error_message'] ) ) {
			throw new Thrive_Dash_Api_ConvertKit_Exception( $response['error_message'] );
		}

		return $forms;
	}

	/**
	 * Subscribe user with the old version of the API (v2).
	 * If the V3 API returns failure, it means it's an old form, created when API had version 2
	 *
	 * It seems that the developers at ConvertKit have learnt to write code yesterday.
	 * API V2 -> API V3 changed the IDs of their FORMS for Christ's sake!
	 * I wish they all get diarrhea
	 *
	 * @param mixed $form_id
	 * @param array $fields
	 *
	 * @return array
	 *
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	protected function _subscribeForm__v2( $form_id, $fields ) {
		$request = sprintf( 'forms/%s/subscribe', $form_id );

		$args = array(
			'email' => $fields['email'],

		);
		if ( ! empty( $fields['name'] ) ) {
			$args['fname'] = $fields['name'];
		}

		$data = $this->_call__v2( $request, $args, 'POST' );

		if ( isset( $data['status'] ) && $data['status'] == 'created' ) {
			return $data;
		}

		if ( isset( $data['status'] ) ) {
			throw new Thrive_Dash_Api_ConvertKit_Exception( 'Error from ConvertKit: ' . $data['status'] );
		}

		throw new Thrive_Dash_Api_ConvertKit_Exception( ( 'Unknown ConvertKit error. Response was: ' . var_export( $data, true ) ) );
	}

	/**
	 * @param $phone
	 *
	 * @return array
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	public function phoneFields( $phone ) {

		$phone_fields  = array();
		$custom_fields = $this->_call( 'custom_fields' );

		if ( is_array( $custom_fields ) && ! empty( $custom_fields['custom_fields'] ) ) {

			foreach ( $custom_fields['custom_fields'] as $field ) {
				if ( strpos( $field['key'], 'phone' ) !== false ) {
					$phone_fields[ $field['key'] ] = $phone;
				}
			}
		}

		return $phone_fields;
	}

	/**
	 * @param $form_id
	 * @param $fields
	 *
	 * @return array|mixed
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	public function subscribeForm( $form_id, $fields ) {
		$request = sprintf( 'forms/%s/subscribe', $form_id );

		if ( ! is_array( $fields ) ) {
			$fields = (array) $fields;
		}

		$args = array(
			'email'  => $fields['email'],
			'fields' => $fields['fields'],
		);

		if ( ! empty( $fields['name'] ) ) {
			$args['first_name'] = $fields['name'];
		}
		$data = $this->_call( $request, $args, 'POST' );
		/**
		 * Error message generated by API v3 when an older form is submitted - this form has unmatched IDs in API v3
		 */
		if ( isset( $data['error'] ) && $data['error'] === 'Not Found' ) {
			return $this->_subscribeForm__v2( $form_id, $fields );
		}

		if ( isset( $data['error'] ) ) {
			throw new Thrive_Dash_Api_ConvertKit_Exception( 'Error from ConvertKit: ' . ( isset( $data['message'] ) ? $data['message'] : $data['error'] ) );
		}

		/**
		 * Handle tags if they are set
		 */
		if ( ! empty( $fields['convertkit_tags'] ) ) {
			$tags = explode( ',', $fields['convertkit_tags'] );
			try {
				$this->addTagsToContact( $args['email'], $tags );
			} catch ( Thrive_Dash_Api_ConvertKit_Exception $e ) {
			}
		}

		if ( ! empty( $data['subscription'] ) ) {
			return $data['subscription'];
		}

		/* some general error */
		throw new Thrive_Dash_Api_ConvertKit_Exception( ( 'Unknown ConvertKit error. Response was: ' . var_export( $data, true ) ) );
	}

	/**
	 * @param $email_address
	 * @param $tags
	 *
	 * @return bool
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	public function addTagsToContact( $email_address, $tags ) {
		if ( ! $email_address || ! $tags ) {
			throw new Thrive_Dash_Api_ConvertKit_Exception( __( 'Missing required parameters for adding tags to ConvertKit contact', 'thrive-dash' ) );

			return false;
		}

		if ( is_array( $tags ) ) {

			/**
			 * Set obj tags
			 */
			$this->setExistingTags();
			foreach ( $tags as $tag_name ) {
				$tag_exists = $this->searchTagInList( $tag_name );

				if ( isset( $tag_exists['id'] ) ) {
					// Assign existing tag to contact/subscriber
					try {
						$this->assignTag( $tag_exists['id'], $email_address );
					} catch ( Thrive_Dash_Api_ConvertKit_Exception $e ) {
					}

					continue;
				}

				try {
					// Create tag and assign it to contact/subscriber
					$this->createAndAssignTag( trim( $tag_name ), $email_address );
				} catch ( Thrive_Dash_Api_ConvertKit_Exception $e ) {
				}
			}
		}
	}

	/**
	 * Set existing tags
	 */
	public function setExistingTags() {
		try {
			$tags                 = $this->_call( 'tags' );
			$this->_existing_tags = is_array( $tags ) && ! empty( $tags['tags'] ) ? $tags['tags'] : array();
		} catch ( Thrive_Dash_Api_ConvertKit_Exception $e ) {
		}
	}

	/**
	 * Returns the tag data [id, name, created_at]
	 *
	 * @param $needle
	 *
	 * @return bool|mixed
	 */
	public function searchTagInList( $needle ) {

		if ( empty( $needle ) ) {
			return false;
		}

		$haystack = (array) $this->_existing_tags;

		foreach ( $haystack as $key => $value ) {
			if ( ! empty( $value['name'] ) && strcasecmp( trim( $needle ), $value['name'] ) === 0 ) {
				return $value;
			}
		}

		return false;
	}

	/**
	 * @param $tag_id
	 * @param $email_address
	 *
	 * @return bool
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	public function assignTag( $tag_id, $email_address ) {

		if ( ! $tag_id || ! $email_address ) {
			return false;
		}

		$request = sprintf( 'tags/%s/subscribe', $tag_id );
		$args    = array(
			'email' => $email_address,
		);
		$assign  = $this->_call( $request, $args, 'POST' );
		if ( is_array( $assign ) && isset( $assign['subscription'] ) ) {
			return true;
		}

		return false;
	}

	/**
	 * @param $tag_name
	 * @param $email_address
	 *
	 * @return bool
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	public function createAndAssignTag( $tag_name, $email_address ) {
		if ( ! $tag_name || ! $email_address ) {
			return false;
		}

		try {
			$created_tag = $this->createTag( $tag_name, $email_address );
		} catch ( Thrive_Dash_Api_ConvertKit_Exception $e ) {
		}

		if ( is_array( $created_tag ) && ! empty( $created_tag['id'] ) ) {
			return $this->assignTag( $created_tag['id'], $email_address );
		}

		return false;
	}

	/**
	 * @param $tag_name
	 * @param $email_address
	 *
	 * @return array|bool|mixed|object
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	public function createTag( $tag_name, $email_address ) {
		if ( ! $tag_name || ! $email_address ) {
			return false;
		}

		$args = array(
			'tag' => array(
				'name' => $tag_name,
			),
		);

		return $this->_call( 'tags', $args, 'POST' );
	}

	public function unsubscribeUser( $email_address, $arguments ) {
		if ( empty( $email_address ) ) {
			return false;
		}

		$arguments['email'] = $email_address;

		return $this->_call( 'unsubscribe', $arguments, 'PUT' );
	}

	/**
	 * Does the calls to the API
	 *
	 * @param $path
	 * @param $args
	 * @param $method
	 *
	 * @return array|WP_Error
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	protected function _call( $path, $args = array(), $method = 'GET' ) {
		$url = $this->build_request_url( $path, $args );
		//build parameters depending on the send method type
		if ( $method == 'GET' ) {
			$request = tve_dash_api_remote_get( $url, $args );
		} elseif ( $method == 'POST' ) {
			$args['api_key'] = $this->key;
			$request         = tve_dash_api_remote_post( $url, $args );
		} elseif ( $method == 'PUT' ) {
			$args['method']  = $method;
			$args['api_key'] = $this->key;

			$request = tve_dash_api_remote_request( $url, $args );
		} else {
			$request = null;
		}

		if ( is_wp_error( $request ) ) {
			throw new Thrive_Dash_Api_ConvertKit_Exception( 'Could not parse the response !' );
		} else {
			$data = json_decode( wp_remote_retrieve_body( $request ), true );
		}

		return $data;
	}

	/**
	 * @param        $path
	 * @param array  $args
	 * @param string $method
	 *
	 * @return mixed
	 *
	 * @throws Thrive_Dash_Api_ConvertKit_Exception
	 */
	protected function _call__v2( $path, $args = array(), $method = 'GET' ) {

		/* v2 way of doing things */
		$args = array_merge( $args, array( 'k' => $this->key, 'v' => '2' ) );

		$url = $this->api_url_base . $path . '?' . http_build_query( $args );
		if ( $method == 'GET' ) {
			$response = tve_dash_api_remote_get( $url, $args );
		} else {
			$response = tve_dash_api_remote_post( $url, $args );
		}
		if ( is_wp_error( $response ) ) {
			throw new Thrive_Dash_Api_ConvertKit_Exception( 'Could not send request to ConvertKit API: ' . $response->get_error_message() );
		}

		return json_decode( wp_remote_retrieve_body( $response ), true );
	}

	/**
	 * Merge default request arguments with those of this request
	 *
	 * @param array $args Request arguments
	 *
	 * @return array        Request arguments
	 */
	public function filter_request_arguments( $args = array() ) {
		return array_merge( $args, array( 'api_key' => $this->key ) );
	}

	/**
	 * Build the full request URL
	 *
	 * @param string $request Request path
	 * @param array  $args    Request arguments
	 *
	 * @return string          Request URL
	 */
	public function build_request_url( $request, $args = array() ) {
		return $this->api_url_base . $this->api_version . '/' . $request . '?' . http_build_query( $this->filter_request_arguments( $args ) );
	}

	/**
	 * Get custom fields
	 *
	 * @return array
	 */
	public function getCustomFields() {

		$response = null;

		try {
			$response = $this->_call( 'custom_fields' );
		} catch ( Exception $e ) {
			$response = $e->getMessage();
		}

		return $response;
	}
}
